package resource

import (
	"database/sql"
	"fmt"
	"strconv"
	"strings"
	"sync"
)
import (
	_ "github.com/denisenkom/go-mssqldb"
)

import (
	dbc "dbConnector"
	"r_log"
	"util"
)

type StockPool struct {
	Level  util.Level  //确认池评级
	Stocks []StockInfo //确认池（按order从小到大排序）
}

type StockInfo struct {
	Order int32
	Stkid util.StkID
	Type  util.ModeType
}

//取消确认池D级使用系统池的逻辑，因此不需要获取系统池信息
//获取确认池股票数据
func getUserPoolsFromDB(db *sql.DB, sp *StockPoolsOnEachServer) error {
	rows, err := db.Query(`P_RecommenderServer_LoadConfirmList`)
	if err != nil {
		return fmt.Errorf("db.Query(): %v", err)
	}
	defer rows.Close()

	userid := new(util.UserID)
	period := new(util.Period)
	stkid := new(util.StkID)
	order := new(int32)
	attribute := new(string)

	userCount := 0
	lastUserid := util.UserID(0)
	lastPeriod := util.Period(0)
	var userSps *[util.PERIOD_COUNT]*StockPool
	var userSp *StockPool
	for rows.Next() {
		if err := rows.Scan(userid, period, stkid, order, attribute); err != nil {
			r_log.Logger.Error("getUserPoolsFromDB(): %v", fmt.Errorf("rows.Scan(): %v", err))
			continue
		}
		modeType, err := convertModeType(*attribute)
		if err != nil {
			r_log.Logger.Error("getUserPoolsFromDB(): %v", fmt.Errorf("convertModeType(): %v", err))
			continue
		}
		si := StockInfo{
			Stkid: *stkid,
			Order: *order,
			Type:  modeType}

		if userCount == 0 || lastUserid != *userid {
			userCount++
			userSps = new([util.PERIOD_COUNT]*StockPool)
			for p := util.PERIOD_DAY; p <= util.PERIOD_HHOUR; p++ {
				(*userSps)[p] = nil
			}
			(sp.Stockpools)[*userid] = userSps
			lastUserid = *userid

			userSp = new(StockPool)
			userSp.Stocks = make([]StockInfo, 0)
			(*userSps)[*period] = userSp
			lastPeriod = *period
		} else {
			if lastPeriod != *period {
				userSp = new(StockPool)
				userSp.Stocks = make([]StockInfo, 0)
				(*userSps)[*period] = userSp
				lastPeriod = *period
			}
		}

		userSp.Stocks = append(userSp.Stocks, si)
	}
	if rows.Err() != nil {
		r_log.Logger.Warn("getUserPoolsFromDB(%v):%v", db, fmt.Errorf("rows.Err(): %v", rows.Err()))
	}
	r_log.Logger.Info("getUserPoolsFromDB(%v):get %v users stock pools", db, userCount)
	return nil
}

//获取确认池评级数据
func getStockPoolsLevelFromDB(db *sql.DB, sp *StockPoolsOnEachServer) error {
	rows, err := db.Query(`P_RecommenderServer_LoadConfirmListLevel`)
	if err != nil {
		return fmt.Errorf("db.Query(): %v", err)
	}
	defer rows.Close()

	userid := new(util.UserID)
	period := new(util.Period)
	scoreNormal := new(util.Level)
	for rows.Next() {
		if err := rows.Scan(userid, period, scoreNormal); err != nil {
			r_log.Logger.Error("getStockPoolsLevelFromDB(): %v", fmt.Errorf("rows.Scan(): %v", err))
			continue
		}
		level, err := util.ConvertLevelForStockPool(*scoreNormal)
		if err != nil {
			r_log.Logger.Error("getStockPoolsLevelFromDB(): %v", fmt.Errorf("ConvertLevelForStockPool(): %v", err))
			continue
		}
		userSps, ok := (sp.Stockpools)[*userid]
		if !ok {
			r_log.Logger.Warn("getStockPoolsLevelFromDB(): %v", fmt.Errorf("Can not find user %v !", *userid))
			continue
		}
		if (*userSps)[*period] == nil {
			r_log.Logger.Warn("getStockPoolsLevelFromDB(): %v", fmt.Errorf("Can not find user stock pool userid=%v, period=%v!", *userid, *period))
			continue
		}
		(*userSps)[*period].Level = level
	}
	if err = rows.Err(); err != nil {
		r_log.Logger.Warn("getStockPoolsLevelFromDB(%v):%v", db, fmt.Errorf("rows.Err(): %v", rows.Err()))
	}

	return nil
}

//解析模型类型
func convertModeType(attribute string) (util.ModeType, error) {
	sd := strings.Split(attribute, ";")
	var mt util.ModeType = 0
	for i := 0; i < len(sd); i++ {
		sa := strings.Split(sd[i], ",")
		if len(sa) >= 2 {
			mode, err := strconv.Atoi(sa[1])
			if err != nil {
				return 0, err
			}
			mt = mt | chooseType(int8(mode))
		}
	}
	return mt, nil
}

func chooseType(usebleType int8) util.ModeType {
	switch usebleType {
	case 0:
		return util.MODE_ALL
	case 1:
		return util.MODE_CHAODIE
	case 2:
		return util.MODE_ZHENDANG
	case 3:
		return util.MODE_QUSHI
	}
	return util.MODE_ALL
}

//更新确认池
func (res *Resource) updateStockPools() error {
	dbc.ServerLock.RLock()
	sl := make([]dbc.ServerInfo, 0, len(dbc.Servers.Account)) //确认池股票数据库地址列表
	for _, si := range dbc.Servers.Account {
		sl = append(sl, *si)
	}
	dbc.ServerLock.RUnlock()

	//获取确认池的股票
	errorlist := make([]error, 0)
	var errorlock sync.Mutex
	var wg sync.WaitGroup
	for _, s := range sl {
		res.SpLock.Lock()
		sp, ok := res.StockPools[s.DataBase]
		if !ok {
			sp = new(StockPoolsOnEachServer)
			sp.IsReady = false
			sp.ServerName = s.DataBase
			sp.Stockpools = make(map[util.UserID](*[util.PERIOD_COUNT]*StockPool))
			res.StockPools[s.DataBase] = sp
		} else {
			if !sp.IsReady {
				sp.Stockpools = make(map[util.UserID](*[util.PERIOD_COUNT]*StockPool))
			}
		}
		res.SpLock.Unlock()
		wg.Add(1)
		go func(server dbc.ServerInfo, stockpools *StockPoolsOnEachServer) {
			defer wg.Done()
			if stockpools.IsReady {
				return
			}
			db := server.DB
			/*			db, err := server.InitSqlServer()
						if err != nil {
							errorlock.Lock()
							errorlist = append(errorlist, fmt.Errorf("initSqlServer(%v): %v", server, err))
							errorlock.Unlock()
							return
						}
						defer db.Close()*/
			//获取确认池
			err := getUserPoolsFromDB(db, stockpools)
			if err != nil {
				db.Close()
				errorlock.Lock()
				errorlist = append(errorlist, fmt.Errorf("getUserPoolsFromDB(%v): %v", server, err))
				errorlock.Unlock()
				return
			}
			//获取确认池评级
			err = getStockPoolsLevelFromDB(db, stockpools)
			if err != nil {
				db.Close()
				errorlock.Lock()
				errorlist = append(errorlist, fmt.Errorf("getStockPoolsLevelFromDB(%v): %v", server, err))
				errorlock.Unlock()
				return
			}
			stockpools.IsReady = true

		}(s, sp)
	}
	wg.Wait()
	if len(errorlist) != 0 {
		return fmt.Errorf("Get err when updateStockPools! %v", errorlist)
	}
	return nil
}
